package dev.hitools.common.utils.download

import android.text.TextUtils
import android.util.Log
import androidx.lifecycle.*
import com.arialyy.aria.core.Aria
import dev.hitools.common.extensions.mainThread
import dev.hitools.common.extensions.toJSON
import dev.hitools.common.utils.MathUtils
import java.io.File

/**
 * 下载的任务
 */
class DownloadTask : InnerDownloadCallback() {

    /**
     * 当前下载的taskId
     */
    private var taskId: Long = 0L

    /**
     * 当前下载的url
     */
    private lateinit var url: String

    /**
     * 保存的路径
     */
    private lateinit var savePath: String

    /**
     * 保存的名称
     */
    private var saveName: String? = null

    /**
     * 用于监听生命周期
     */
    private var lifecycle: Lifecycle? = null

    /**
     * 进度监听
     */
    private var onProgressListener: DownloadManager.OnProgressListener? = null
    private var onProgressBlock: OnDownloadProgressBlock? = null

    /**
     * 状态改变
     */
    private var onStatusChangedListener: DownloadManager.OnStatusChangedListener? = null
    private var onStatusChangedBlock: OnDownloadStatusChangedBlock? = null

    /**
     * 最终的下载文件的信息
     * 如果没有设置saveName，则使用服务器返回的文件名
     */
    private val downloadFile
        get() = if (TextUtils.isEmpty(saveName)) {
            savePath
        } else {
            savePath + File.separator + saveName
        }

    /**
     * 下载url
     */
    fun url(url: String): DownloadTask {
        this.url = url
        return this
    }

    /**
     * 设置文件的保存位置
     */
    fun savePath(savePath: String): DownloadTask {
        this.savePath = savePath
        return this
    }

    /**
     * 设置文件的保存名称，可以不设置
     */
    fun saveName(saveName: String): DownloadTask {
        this.saveName = saveName
        return this
    }

    /**
     * 下载进度的回调监听
     */
    fun setOnProgressListener(listener: DownloadManager.OnProgressListener): DownloadTask {
        onProgressListener = listener
        return this
    }

    /**
     * 下载进度的回调监听
     */
    fun setOnProgressListener(listener: OnDownloadProgressBlock): DownloadTask {
        onProgressBlock = listener
        return this
    }

    /**
     * 下载状态的回调监听
     */
    fun setOnStatusChangedListener(listener: DownloadManager.OnStatusChangedListener): DownloadTask {
        onStatusChangedListener = listener
        return this
    }

    /**
     * 下载状态的回调监听
     */
    fun setOnStatusChangedListener(listener: OnDownloadStatusChangedBlock): DownloadTask {
        onStatusChangedBlock = listener
        return this
    }


    @Throws(Exception::class)
    fun start(): DownloadTask {
        checkParams()
        taskId = Aria.download(this)
            .load(url)
            .setFilePath(downloadFile)
            .ignoreCheckPermissions()
            .ignoreFilePathOccupy()
            .create()

        if (taskId == -1L) {
            notifyDownloadFailed(-1, "create task failed")
        }

        return this
    }

    /**
     * 恢复下载
     */
    fun resume(): DownloadTask {
        Aria.download(this)
            .load(taskId)
            .resume()
        return this
    }

    /**
     * 终止下载
     */
    fun intercept(): DownloadTask {
        Aria.download(this)
            .load(taskId)
            .cancel()
        return this
    }

    /**
     * 暂停任务
     */
    fun pause(): DownloadTask {
        Aria.download(this)
            .load(taskId)
            .stop()
        return this
    }

    /**
     * 增加生命周期的监听
     */
    fun setLifeCycle(lifecycle: Lifecycle) {
        this.lifecycle = lifecycle
        lifecycle.addObserver(LifeCycleChecker())
    }

    fun isDownloading(): Boolean {
        return Aria.download(this).load(taskId).isRunning
    }

    override fun onTaskStart(task: com.arialyy.aria.core.task.DownloadTask) {
        super.onTaskStart(task)
        notifyStatusChanged(task, DownloadStatus.Start)
    }

    override fun onTaskCancel(task: com.arialyy.aria.core.task.DownloadTask) {
        super.onTaskCancel(task)
        notifyStatusChanged(task, DownloadStatus.Canceled)
    }

    override fun onTaskFail(task: com.arialyy.aria.core.task.DownloadTask, e: Exception?) {
        super.onTaskFail(task, e)

        if (isCurrentTask(task)) {
            notifyDownloadFailed(101, "download failed")
        }
    }

    override fun onTaskComplete(task: com.arialyy.aria.core.task.DownloadTask) {
        notifyDownloadComplete(task)
    }

    override fun onTaskRunning(task: com.arialyy.aria.core.task.DownloadTask) {
        super.onTaskRunning(task)
        notifyProgressChanged(task)
    }

    /**
     * 是否是当前的task
     */
    private fun isCurrentTask(task: com.arialyy.aria.core.task.DownloadTask): Boolean {
        return task.entity.id == taskId
    }

    /**
     * 检测必要参数是否有效
     */
    private fun checkParams(): Boolean {
        when {
            TextUtils.isEmpty(url) -> {
                throw IllegalStateException("url is empty")
            }
            TextUtils.isEmpty(savePath) -> {
                throw IllegalStateException("savePath is empty")
            }

            else -> return true
        }
    }

    private fun notifyDownloadFailed(code: Int, message: String) = mainThread {
        val info = DownloadStatusInfo(DownloadStatus.Failed)
        info.errorCode = code
        info.errorMessage = message

        onStatusChangedBlock?.let { it(info) }
        onStatusChangedListener?.onStatusChanged(info)
    }

    private fun notifyDownloadComplete(task: com.arialyy.aria.core.task.DownloadTask) = mainThread {
        if (!isCurrentTask(task)) {
            return@mainThread
        }

        val info = DownloadStatusInfo(DownloadStatus.Complete)
        info.file = File(task.filePath)

        onStatusChangedBlock?.let { it(info) }
        onStatusChangedListener?.onStatusChanged(info)
    }

    private fun notifyStatusChanged(task: com.arialyy.aria.core.task.DownloadTask, status: DownloadStatus) = mainThread {
        if (!isCurrentTask(task)) {
            return@mainThread
        }
        val info = DownloadStatusInfo(status)

        onStatusChangedBlock?.let { it(info) }
        onStatusChangedListener?.onStatusChanged(info)
    }

    private fun notifyProgressChanged(task: com.arialyy.aria.core.task.DownloadTask) = mainThread {
        if (!isCurrentTask(task)) {
            return@mainThread
        }
        val percent = MathUtils.rounding(task.currentProgress * 100F / task.fileSize, 2).toFloat()

        onProgressBlock?.invoke(percent, task.speed)
        onProgressListener?.progress(percent, task.speed)
    }

    /**
     * 生命周期的监听
     */
    private inner class LifeCycleChecker : DefaultLifecycleObserver {
        override fun onDestroy(owner: LifecycleOwner) {
            super.onDestroy(owner)
            lifecycle?.removeObserver(this)
            destroy()
        }
    }
}